package com.qf.controller;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.qf.aop.annocation.FormToken;
import com.qf.common.BusinessException;
import com.qf.common.ExceptionStatus;
import com.qf.common.ResultEntity;
import com.qf.common.ShopConstatns;
import com.qf.entity.Email;
import com.qf.entity.User;
import com.qf.feign.api.CarService;
import com.qf.feign.api.UserService;
import com.qf.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.annotation.Around;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/ssoController")
@Slf4j
public class SSOController {

    @Autowired
    private UserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate; // key和value使用字符串的形式序列化
//    private RedisTemplate redisTemplate; // key和value都是采用对象的序列化的方式 name:admin

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private CarService carService;


    @Value("${email.emailExchangeName}")
    private String emailExchangeName;

    @RequestMapping("/sendCode/{email}")
    public void sendCode(@PathVariable String email) {
        log.debug(email);

        // 1.生成一个四位数的验证码
        // 第一个参数：随机数的长度
        // 第二个参数是：生成的随机数中是否包含字母
        // 第三个参数：生成的随机数中是否包含数组
        String code = RandomStringUtils.random(4, false, true);

        // 2.创建一个email对象
        // 创建一个邮件对象
        Email e = new Email();
        e.setTitle("2101在线商城新用户注册");
        e.setContent("验证码:" + code);
        e.setTo(new String[]{email});

        // 3.保存验证码到redis // reigster_user_email_854569279@qq.com
        stringRedisTemplate.opsForValue().set(ShopConstatns.REGISTER_USER_EMAIL + email, code, 30, TimeUnit.SECONDS);

        // 4.把这个邮件对象发送给MQ
        rabbitTemplate.convertAndSend(emailExchangeName, "email.send", e);
    }

    @RequestMapping("/getUserByUsername")
    public Map<String, String> getUserByUsername(@RequestParam("param") String username) {

        Map<String, String> map = new HashMap<>();

        // 1.根据用户名称查询对象
        User user = userService.findUser("username", username);

        // 2.判断用户是否存在
        if (user == null) {
            // 可以注册
            map.put("status", "y");
            map.put("info", "可以注册");
        } else {
            map.put("status", "n");
            map.put("info", "该用户已经被注册");
            // 该用户名已经被注册了
        }
        return map;
    }

    @RequestMapping("/test")
    public void test() {
        log.debug("test");
    }


    // domain：我都买呢
    @FormToken // 加了这个注解的方法就表示需要表单验证
    @RequestMapping("/registerUser")
    public ResultEntity registerUser(@RequestBody com.qf.domain.User dUser) throws IOException {

        // 1.先要做验证码的校验
        // 1.1 先获取用户传递的验证码
        String formCode = dUser.getCode();

        // 1.2 查询redis中这个用户的验证码
        String redisCode = stringRedisTemplate.opsForValue().get(ShopConstatns.REGISTER_USER_EMAIL + dUser.getEmail());

        log.debug("{},{}", dUser.getEmail(), redisCode);

        // 1.3判断
        if (StringUtils.isEmpty(redisCode) || !redisCode.equals(formCode)) {
//            throw new BusinessException(1002,"验证码已过期"); // 这个可以优化
            throw new BusinessException(ExceptionStatus.VALICODE_ERROR); // 这个可以优化
        }

        // 2.密码的加密
        String dbPassword = BCrypt.hashpw(dUser.getPassword(), BCrypt.gensalt());
        dUser.setPassword(dbPassword); // 用密文覆盖掉明文

        // 4.把domain转成entity
        User eUser = new User(); // com.qf.entity.User
        BeanUtils.copyProperties(dUser, eUser); // 只要两个对象的中的属性一直，就会拷贝过去
        log.debug(eUser.toString());

        // 5.保存到数据库
        Boolean aBoolean = userService.addUser(eUser);

        // 6.提示用户
        return ResultEntity.success();
    }

    @RequestMapping("/login")
    public ResultEntity login(@RequestBody Map<String, String> param
            , @CookieValue(name = ShopConstatns.SHOP_CAT_ANNO_NAME, required = false, defaultValue = "") String annoId) {

        String username = param.get("username");
        String password = param.get("password");
        String returnUrl = param.get("returnUrl");

        // 1.先根据用户名查询对象
        User dbUser = userService.findUser("username", username);

        // 2.判断dbUser是否为空
        if (dbUser == null) {
            throw new BusinessException(ExceptionStatus.AUTH_ERROR);
        }

        // 3.密码对比
        boolean checkpw = BCrypt.checkpw(password, dbUser.getPassword());
        if (!checkpw) {
            throw new BusinessException(ExceptionStatus.AUTH_ERROR);
        }
        dbUser.setPassword(null);

        // 生成token
        Map<String, String> map = new HashMap<>();
        map.put("username", dbUser.getUsername());
        map.put("id", dbUser.getId().toString());
        map.put("email", dbUser.getEmail());
//        map.put("role")
        String token = JWTUtils.createToken(map, 60 * 60 * 24 * 7);

        // 购车的合并
        if (!StringUtils.isEmpty(annoId)) {
            carService.mergeCar(annoId, dbUser.getId());
        }

        // 4.登录成功
        return ResultEntity.success(token);
    }

    @RequestMapping("/findUserByUsername/{username}")
    public ResultEntity findUserByUsername(@PathVariable String username) {

        // 1.先根据用户名查询对象
        User dbUser = userService.findUser("username", username);

        // 2.判断dbUser是否为空
        if (dbUser == null) {
            throw new BusinessException(ExceptionStatus.AUTH_ERROR);
        }

        // 生成一个token
        Map<String, String> map = new HashMap<>();
        map.put("username", dbUser.getUsername());
        String token = JWTUtils.createToken(map, 60 * 60 * 2);

        // 4.给用户的邮箱发送一个邮件
        Email email = new Email();
        email.setTitle("2101商城用户修改密码");
        email.setContent("修改密码点击<a href = 'http://localhost/shop-sso/toUpdatePasswordPage?token=" + token + "'>这里</a>");
        email.setTo(new String[]{dbUser.getEmail()});

        rabbitTemplate.convertAndSend(emailExchangeName, "email.send", email);

        // 截取邮箱的一部分显示给用户
        String e = dbUser.getEmail();
        String substring = e.substring(4, e.indexOf("@"));
        String subEmail = e.replace(substring, "****");


        // 3.返回用户的邮箱
        return ResultEntity.success(subEmail);
    }

    @RequestMapping("/updatePassword")
    public ResultEntity updatePassword(@RequestBody Map<String, String> map) {

        // 1.先从Map中获取token和密码
        String token = map.get("token");
        String password = map.get("password");

        // 2.先做延签
        DecodedJWT verifier = JWTUtils.verifier(token);

        // 3.延签成功后从token中获取用户名
        String username = JWTUtils.getClaim(verifier, "username");

        // 4.对密码加密
        String hashpw = BCrypt.hashpw(password, BCrypt.gensalt());

        // 5.更新数据库
        User user = userService.findUser("username", username);
        user.setPassword(hashpw);
        userService.updateUser(user);

        // 6、响应用户
        return ResultEntity.success();
    }

    @RequestMapping("/getUserInfoByToken")
    public ResultEntity getUserInfoByToken(HttpServletRequest request) {

        // 1.获取token
        String token = request.getHeader("Authorization");

        if (StringUtils.isEmpty(token)) {
            return ResultEntity.error("token为空");
        }

        // 2.延签
        DecodedJWT verifier = JWTUtils.verifier(token);

        // 3.取出用户的信息
        String username = JWTUtils.getClaim(verifier, "username");

        // 4.响应用户名字
        return ResultEntity.success(username);
    }

}
